package com.pl.redis;

import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @author shent
 */
@Service
public class RedisServiceAct {
    @Resource
    RedisService redisService;

    /**
     * (有些问题:因为是按照每分钟键过期来实现的,
     * 若是用户在一分钟的末尾10秒访问100次,
     * 在第二个一分钟的开头访问100次,
     * 就会造成20秒内访问200次的问题)
     * <p>
     * 前端让用户每次发请求都调用一次这个方法
     * 限制,每个用户每分钟 访问 最多 100 次,减小服务器压力
     *
     * @param key 键 "user:{id}"
     */
    public void limitUserAskTimeWay1(String key) {
        if (redisService.isExists(key)) {
            //用户一分钟内访问的次数
            Long times = redisService.incrString(key);
            if (times > 100) {
                System.out.println("访问频率超过了限制,请稍后再试");
                //具体的一些限制逻辑
            }
        } else {
            //这里加了事务,防止设置完key,某些特殊原因导致没设置过期时间,导致键永久存在了,用户永远只能访问100次的问题
            redisService.multi();
            redisService.incrString(key);
            redisService.setExpire(key, 60, TimeUnit.SECONDS);
            redisService.exec();
        }
    }

    /**
     * (优化版)
     * 把每次访问的时间记录到 list 集合中,当 list 集合中的记录数量 >100 时
     * 来计算第一次访问和最后一次访问时间的间隔是否小于1分钟,
     * 如果小于一分钟,则表明在一分钟内用户访问次数超过了100次,应该受到限制
     * <p>
     * 限制,每个用户每分钟 访问 最多 100 次,减小服务器压力
     * 此处 list 的 key 的 value 存的是时间戳
     *
     * @param key 键
     */
    public void limitUserAskTimeWay2(String key) {
        Long listLength = redisService.getListLength(key);
        if (listLength < 100) {
            redisService.lPushList(key, System.currentTimeMillis() + "");
        } else {
            //从右往左数第一个元素的值
            long times = (Long) redisService.lIndexList(key, -1);
            //如果第一次访问的时间和当前时间相差小于 60 秒
            if (System.currentTimeMillis() - times < 60 * 1000) {
                System.out.println("访问频率超过了限制,请稍后再试");
                //具体的一些限制逻辑
            } else {
                redisService.lPushList(key, System.currentTimeMillis() + "");
                //删除最早的元素,保留最近100个记录
                redisService.lTrimList(key, 0, 99);
            }
        }
    }

    public void queueReal() {
        //入队
        redisService.lPushList("list", "1");
        //出队,60秒内如果list中没有元素则返回空
        redisService.rPopList("list", 60, TimeUnit.SECONDS);
    }


}
